﻿using Blm.PgsqlDriver.Helpers;
using Blm.Utils.Extensions;
using Blm.Utils.Utility;
using Dapper;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Npgsql;
using Pipelines.Sockets.Unofficial.Arenas;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using VisionCloud.Core.Model.Ms;
using VisionCloud.Domain.Common;
using VisionCloud.Domain.DtoModel.Fms;
using VisionCloud.Domain.DtoModel.Ms;
using VisionCloud.Domain.Extension;
using VisionCloud.Domain.Repository.Interface.Fms;
using VisionCloud.Domain.Repository.Interface.Ms;
using VisionCloud.Domain.UnitOfWork;
using VisionCloud.Service.Fms;
using VisionCloud.Utility;
using static VisionCloud.Core.Model.Ms.MsHouseMap;
using Array = System.Array;

namespace VisionCloud.Service.Ms
{
    /// <summary>
    /// 热力图服务类
    /// </summary>
    public class HouseMapService
    {
        public IUnitOfWork UnitOfWork { get; set; }

        public IMsProjectRepository MsProjectRepository { get; set; }

        public IMsHouseMapRepository MsHouseMapRepository { get; set; }

        public IMsPointTypeRepository MsPointTypeRepository { get; set; }

        public IMsMeasureItemRepository MsMeasureItemRepository { get; set; }

        public IMsHouseMapPointRepository MsHouseMapPointRepository { get; set; }

        public IMsHouseMapDetailsRepository MsHouseMapDetailsRepository { get; set; }

        public IMsMeasureTemplateRepository MsMeasureTemplateRepository { get; set; }

        public IMsPointTypeMeasureItemRepository MsPointTypeMeasureItemRepository { get; set; }

        public IMsHouseMapBuildingFloorRepository MsHouseMapBuildingFloorRepository { get; set; }

        public IFmsProjectBuildingFloorRepository FmsProjectBuildingFloorRepository { get; set; }
        public IMsProjectEditLogRepository MsProjectEditLogRepository { get; set; }

        public ProjectService ProjectService { get; set; }

        public ProjectDCService ProjectDCService { get; set; }

        public AutomaticService AutomaticService { get; set; }

        public ILogger<ProjectService> Logger { get; set; }

        private readonly string FileServer;

        private readonly string UploadFile;

        private readonly string UplaodSonFile;

        private readonly string AlgorithmReport;

        private OperatorInfo TokenModel => OperatorProvider.Get();

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="cfg"></param>
        public HouseMapService(IConfiguration cfg)
        {
            FileServer = cfg["FileServer"];
            UploadFile = cfg["FileUploadFileMaster"];
            UplaodSonFile = cfg["FileUploadFileSon"];
            AlgorithmReport = cfg["AlgorithmReport"];
        }

        /// <summary>
        /// 获取项目户型图
        /// </summary>
        /// <param name="condition"></param>
        /// <returns></returns>
        public async Task<ApiPageResult> GetProjectHouseMap(MsHouseMapCondition condition)
        {
            return await MsHouseMapRepository.GetHouseMap(condition);
        }

        /// <summary>
        /// 上传图片权限验证
        /// </summary>
        /// <param name="model"></param>
        /// <exception cref="OperationException"></exception>
        private async Task<MsProject> CheckUploadAuth(UploadHouseMapModel model)
        {
            if (string.IsNullOrEmpty(model.Name))
                throw new OperationException("YB0010".SLocalize());

            if (model.Name.Length > 20)
            {
                throw new OperationException("YB0100".SLocalize());
            }

            if (model.ProjectId == Guid.Empty)
            {
                throw new OperationException("YB0101".SLocalize());
            }

            CheckUploadFileParameter(model.Maps);
            var project = await CheckUserProjectAuth(model.ProjectId);

            var housemap = await MsHouseMapRepository.FirstOrDefaultAsync(x => x.ProjectId == model.ProjectId && x.Name == model.Name && !x.IsDeleted);
            if (housemap != null)
                throw new OperationException($"户型图名称【{model.Name}】已存在,请更换名称");

            //文件流验证文件格式是否为指定图形格式
            Stream stream = model.Maps.FirstOrDefault().OpenReadStream();
            if (model.DataType == 0 && !FileInfoUtil.IsPicture(stream))
            {
                throw new OperationException("YB0107".SLocalize());
            }
            if (stream.Length > 5 * 1024 * 1024)
            {
                throw new OperationException("YB0108".SLocalize());
            }

            return project;
        }

        /// <summary>
        /// 文件上传参数检查
        /// </summary>
        /// <param name="maps"></param>
        /// <param name="fileFilt"></param>
        /// <exception cref="OperationException"></exception>
        private static void CheckUploadFileParameter(IFormFileCollection maps, string fileFilt = ".gif|.jpg|.jpeg|.png|.dxf|.json")
        {
            if (maps.Count == 0)
            {
                //未检测到文件
                throw new OperationException("YB0102".SLocalize());
            }

            if (maps.Count > 1)
            {
                //仅支持上传单个文件
                throw new OperationException("OnlySingleFile".SLocalize());
            }

            //文件格式检测
            var file = maps.FirstOrDefault();
            var fileExtension = Path.GetExtension(file.FileName);
            if (fileExtension == null)
            {
                throw new OperationException("YB0106".SLocalize());
            }
            if (fileFilt.IndexOf(fileExtension.ToLower(), StringComparison.Ordinal) <= -1)
            {
                throw new OperationException("YB0107".SLocalize());
            }
        }

        /// <summary>
        /// 上传户型图
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        /// <exception cref="OperationException"></exception>
        public async Task<ApiResult> UploadHouseMapFile(UploadHouseMapModel model)
        {
            var project = await CheckUploadAuth(model);

            switch (model.DataType)
            {
                case 0:
                    return await UploadHouseMap(model);

                case 1:
                case 2:
                    return await UploadDxfOrJsonFile(model, project.ProjectNo);

                default:
                    throw new OperationException("DataTypeNotSupported".SLocalize());
            }
        }

        /// <summary>
        /// 上传dxf、json文件，然后调用自动标注算法生成户型图底图和站点信息json文件
        /// </summary>
        /// <param name="model"></param>
        /// <param name="projectNo"></param>
        /// <returns></returns>
        private async Task<ApiResult> UploadDxfOrJsonFile(UploadHouseMapModel model, string projectNo)
        {
            await Contracts.Frequency($"housemap_upload_limit_all_{Guid.NewGuid()}", 10, TimeSpan.FromSeconds(90), StartupServer.CommonLocalizer["YB0449"].Value, false);
            //户型图Id
            var houseMapId = Guid.NewGuid();

            //保存文件到指定目录
            var (fileName, fileUrl) = await SaveFileToWwwroot(model.Maps, houseMapId, projectNo);

            //调用自动标注算法
            await CreateHouseMapByArithmetic(new CreateHouseMapDto
            {
                ProjectId = model.ProjectId,
                ProjectNo = projectNo,
                HouseMapId = houseMapId,
                HouseMapName = model.Name,
                DataType = model.DataType,
                MapType = (EnumHouseMapType)model.MapType,
                FileName = fileName,
                FileUrl = fileUrl
            });

            return new ApiResult { Code = AjaxCode.Success, Result = houseMapId };
        }

        /// <summary>
        /// 上传dxf，然后调用自动标注算法生成户型图底图和站点信息json文件
        /// </summary>
        /// <returns></returns>
        private async Task<ApiResult> UpdateHouseMapByDxf(HouseMapUpdateByDxfDto model, MsProject project, MsHouseMap houseMap)
        {
            var (fileName, fileUrl) = await SaveFileToWwwroot(model.Maps, model.HouseMapId, project.ProjectNo);

            //调用自动标注算法
            await UpdateHouseMapByArithmetic(project, houseMap, fileName, fileUrl);

            return new ApiResult { Code = AjaxCode.Success, Result = model.HouseMapId };
        }

        /// <summary>
        /// 保存文件到wwwroot
        /// </summary>
        /// <param name="maps"></param>
        /// <param name="houseMapId"></param>
        /// <param name="projectNo"></param>
        /// <returns></returns>
        private async Task<(string fileName, string fileUrl)> SaveFileToWwwroot(IFormFileCollection maps, Guid houseMapId, string projectNo)
        {
            CreateWwwrootDir();
            var fileBytes = FileInfoUtil.StreamToBytes(maps[0].OpenReadStream());
            string path = Path.Combine(StartupServer.ContentRootPath, "wwwroot/" + UploadFile + "/" + UplaodSonFile + "/" + maps[0].FileName);
            string dir = Path.GetDirectoryName(path);
            string ext = Path.GetExtension(path);
            var savePath = Path.Combine(dir, $"{projectNo}-{houseMapId}{ext}");
            await File.WriteAllBytesAsync(savePath, fileBytes);

            var fileName = Path.GetFileName(savePath);
            var fileUrl = $"{FileServer}/{UploadFile}/{UplaodSonFile}/{fileName}";

            return (fileName, fileUrl);
        }

        /// <summary>
        /// 户型图上传逻辑
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        /// <exception cref="OperationException"></exception>
        private async Task<ApiResult> UploadHouseMap(UploadHouseMapModel model)
        {
            try
            {
                //插入户型图表记录
                var map = new MsHouseMap
                {
                    ProjectId = model.ProjectId,
                    HouseMapId = Guid.NewGuid(),
                    CreatedBy = TokenModel.Id,
                    CreatedDate = DateTime.Now,
                    LastUpdatedBy = TokenModel.Id,
                    LastUpdatedDate = DateTime.Now,
                    Name = string.IsNullOrWhiteSpace(model.Name) ? model.Maps[0].FileName : model.Name,
                    //Status = (MsHouseMap.EnumHouseMapType)model.MapType == MsHouseMap.EnumHouseMapType.非标准层
                    //? MsHouseMap.EnumHouseMapStatus.启用 : MsHouseMap.EnumHouseMapStatus.禁用,
                    Status = MsHouseMap.EnumHouseMapStatus.启用,
                    MeasurePoints = string.Empty,
                    MapType = (MsHouseMap.EnumHouseMapType)model.MapType
                };

                var avatarData = FileInfoUtil.StreamToBytes(model.Maps[0].OpenReadStream());
                CreateWwwrootDir();

                string path = Path.Combine(StartupServer.ContentRootPath, "wwwroot/" + UploadFile + "/" + UplaodSonFile + "/" + model.Maps[0].FileName);

                //转png缩略图
                using (Image<Rgba32> image = Image.Load<Rgba32>(avatarData))
                {
                    // 图片压缩逻辑会导致户型图变形，故注释压缩逻辑--黄钧航
                    //image.Mutate(pointInModel => pointInModel
                    //        .Resize(600, (image.Height / image.Width) * 600)
                    //        );
                    string dir = Path.GetDirectoryName(path);
                    string ext = Path.GetExtension(path);
                    path = Path.Combine(dir, map.HouseMapId.ToString() + ext);
                    image.Save(path);
                }
                FileInfo fi = new FileInfo(path);
                byte[] buff = new byte[fi.Length];
                FileStream fs = fi.OpenRead();
                fs.Read(buff, 0, Convert.ToInt32(fs.Length));
                fs.Close();
                string strPath = model.Maps[0].FileName;
                string extension_last = Path.GetFileNameWithoutExtension(strPath);
                map.Image_Base = strPath.Replace(extension_last, map.HouseMapId.ToString());

                MsHouseMapRepository.Add(map);
                MsProjectRepository.UpdateProjectVersion(model.ProjectId);
                await UnitOfWork.SaveChangesAsync();

                Logger.LogInformation($"【{TokenModel.Name}】修改了户型图：[{model.ProjectId}]");

                //删除临时文件
                //File.Delete(path);
                var result = new ApiResult();
                result.Code = AjaxCode.Success;
                result.Result = map.HouseMapId;
                return result;
            }
            catch (Exception ex)
            {
                Logger.LogError(ex, $"【{TokenModel.Name}】修改户型图：[{model.ProjectId}]失败");
                throw new OperationException($"YB0109".SLocalize());
            }
        }

        /// <summary>
        /// 通过Dxf文件调用自动标注算法更新户型图
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        /// <exception cref="OperationException"></exception>
        public async Task<ApiResult> UpdateHouseMapByDxf(HouseMapUpdateByDxfDto model)
        {
            if (model.HouseMapId == Guid.Empty)
                throw new OperationException("YB0009".SLocalize());

            CheckUploadFileParameter(model.Maps, ".dxf");

            var houseMap = await MsHouseMapRepository.FirstOrDefaultAsync(p => p.HouseMapId == model.HouseMapId && !p.IsDeleted);
            if (houseMap == null)
            {
                //户型图不存在或已删除
                throw new OperationException("YB0120".SLocalize());
            }
            var project = await CheckUserProjectAuth(houseMap.ProjectId);

            return await UpdateHouseMapByDxf(model, project, houseMap);
        }

        /// <summary>
        /// 如果不存在wwwroot文件上传目录则创建
        /// </summary>
        private void CreateWwwrootDir()
        {
            if (!Directory.Exists(Path.Combine(StartupServer.ContentRootPath, "wwwroot\\" + UploadFile)))
            {
                Directory.CreateDirectory(Path.Combine(StartupServer.ContentRootPath, UploadFile));
                if (!Directory.Exists(Path.Combine(StartupServer.ContentRootPath, "wwwroot/" + UploadFile + "/" + UplaodSonFile)))
                {
                    Directory.CreateDirectory(Path.Combine(StartupServer.ContentRootPath, "wwwroot/" + UploadFile + "/" + UplaodSonFile));
                }
            }
        }

        /// <summary>
        /// 获取户型图信息
        /// </summary>
        /// <param name="HouseMapId">户型图编号</param>
        /// <returns></returns>
        /// <exception cref="OperationException"></exception>
        public async Task<MsHouseMapDto> GetHouseMapById(Guid HouseMapId)
        {
            if (HouseMapId == Guid.Empty)
            {
                throw new OperationException("YB0009".SLocalize());
            }
            return await MsHouseMapRepository.GetHouseMap(HouseMapId);
        }

        /// <summary>
        /// 获取户型图URL
        /// </summary>
        /// <param name="HouseMapId">户型图编号</param>
        /// <returns></returns>
        public async Task<ApiResult> GetHouseMapBase(Guid HouseMapId)
        {
            if (HouseMapId == Guid.Empty)
            {
                throw new OperationException("YB0009".SLocalize());
            }

            var img_base = await MsHouseMapRepository.GetHouseMapBase(HouseMapId);

            if (string.IsNullOrEmpty(img_base))
                throw new OperationException("YB0120".SLocalize());

            return new ApiResult { Code = AjaxCode.Success, Result = img_base };
        }

        /// <summary>
        /// 获取户型图URL
        /// </summary>
        /// <param name="taskId"></param>
        /// <returns></returns>
        /// <exception cref="OperationException"></exception>
        public async Task<ApiResult> GetHouseMapBaseUrl(Guid taskId)
        {
            var img_url = await MsHouseMapRepository.GetHouseMapBaseUrl(taskId);

            if (string.IsNullOrEmpty(img_url))
                throw new OperationException("YB0120".SLocalize());

            return new ApiResult { Code = AjaxCode.Success, Result = img_url };
        }

        /// <summary>
        /// 根据户型图Id获取楼栋楼层
        /// </summary>
        /// <param name="houseMapId"></param>
        /// <returns></returns>
        /// <exception cref="OperationException">户型图编号</exception>
        public async Task<string[][]> GetSelectedBuildingFloorByHouseMap(Guid houseMapId)
        {
            if (houseMapId == Guid.Empty)
            {
                throw new OperationException("YB0009".SLocalize());
            }
            var houseMapDetailForProjectList = await MsHouseMapDetailsRepository.WhereAsync(i => i.HouseMapId == houseMapId);
            if (houseMapDetailForProjectList == null || houseMapDetailForProjectList.Count() <= 0)
            {
                return new string[][] { };
            }
            else
            {
                return houseMapDetailForProjectList.Select(i => new string[] { i.BuildingName, i.FloorName }).ToArray();
            }
        }

        /// <summary>
        /// 根据项目Id获取楼栋楼层
        /// </summary>
        /// <param name="projectGuid"></param>
        /// <param name="houseMapId"></param>
        /// <returns></returns>
        /// <exception cref="OperationException"></exception>
        public async Task<ElCascaderTreeDataDto[]> GetBuildingFloorTreeDataByProjectID(Guid projectGuid, Guid houseMapId)
        {
            if (projectGuid == Guid.Empty)
            {
                throw new OperationException("YB0008".SLocalize());
            }
            if (houseMapId == Guid.Empty)
            {
                throw new OperationException("YB0009".SLocalize());
            }
            var projectInfo = await ProjectService.GetProjectInfo(projectGuid.ToString());
            if (projectInfo.DetailsInfo == null)
            {
                throw new OperationException("YB0111".SLocalize());
            }
            var result = new List<ElCascaderTreeDataDto>();
            var houseMapDetailForProjectList = await MsHouseMapDetailsRepository.WhereAsync(i => i.ProjectId == projectGuid && i.HouseMapId != houseMapId && !i.IsDeleted);
            var isCanEdit = TokenModel.RoleNameList.Contains("公司管理员") || TokenModel.RoleNameList.Contains("测量管理员");
            foreach (var item in projectInfo.DetailsInfo)
            {
                var building = new ElCascaderTreeDataDto()
                {
                    value = item.Building,
                    label = item.Building + "YBBuild".SLocalize(),
                };
                var buildingList = houseMapDetailForProjectList.Where(i => i.BuildingName == item.Building).ToList();

                building.children = GetBuildingFloor(item.Floor.ToInt32(), buildingList, isCanEdit);
                building.disabled = !isCanEdit && building.children.All(item => item.disabled);

                result.Add(building);
            }
            return result.ToArray();
        }

        /// <summary>
        /// 获取楼栋楼层
        /// </summary>
        /// <param name="totoalFloorNumber"></param>
        /// <param name="hmdList"></param>
        /// <param name="isCanEdit"></param>
        /// <returns></returns>
        private ElCascaderTreeDataDto[] GetBuildingFloor(int totoalFloorNumber, List<MsHouseMapDetails> hmdList, bool isCanEdit)
        {
            var result = new List<ElCascaderTreeDataDto>();
            for (int i = 0; i < totoalFloorNumber; i++)
            {
                var item = new ElCascaderTreeDataDto();
                item.label = item.value = (i + 1).ToString();
                item.label = item.label + "YBLayer".SLocalize();
                item.children = null;
                item.disabled = !isCanEdit || hmdList.Any(j => item.value == j.FloorName);
                result.Add(item);
            }
            return result.ToArray();
        }

        /// <summary>
        /// 逻辑删除户型图
        /// </summary>
        /// <param name="HouseMapId">户型图编号</param>
        /// <returns></returns>
        public async Task RemoveHouseMap(Guid HouseMapId)
        {
            MsHouseMapRepository.RemoveById(HouseMapId);
            await UnitOfWork.SaveChangesAsync();
            Logger.LogInformation($"【{OperatorProvider.Get().Name}】删除户型图：[{HouseMapId}]");
        }

        /// <summary>
        /// 批量逻辑删除户型图
        /// </summary>
        /// <param name="ids"></param>
        /// <returns></returns>
        /// <exception cref="OperationException"></exception>
        public async Task RemoveHouseMaps(List<Guid> ids)
        {
            MsProject msProject = null;
            foreach (var id in ids)
            {
                //新需求：已经发布过、使用过得允许删除，Modified On 2022/08/27
                //bool result = await MsHouseMapRepository.IsHouseMapUsed(id);
                //if (result)
                //{
                //    throw new OperationException("YB0112".SLocalize(entity.Name));
                //}
                //result = await MsHouseMapRepository.HouseMapForProjectIsPublice(id);
                //if (result)
                //    throw new OperationException("YB0113".SLocalize(entity.Name));
                var entity = await MsHouseMapRepository.GetByIdAsync(id);
                var housemapName = entity.Name;
                entity.Name = $"{housemapName}-{id.ToString().Substring(id.ToString().Length - 4, 4)}";    // 删除时修改名字
                entity.SetOperatorInfoWhenRemove();
                MsHouseMapRepository.Update(entity, x => new { x.IsDeleted, x.Name, x.LastUpdatedBy, x.LastUpdatedDate });
                var dbList = await MsHouseMapDetailsRepository.WhereAsync(i => i.HouseMapId == id);
                MsHouseMapDetailsRepository.RemoveRange(dbList);
                if (msProject == null)
                {
                    msProject = await MsProjectRepository.GetByIdAsync(entity?.ProjectId);
                    if (msProject != null && msProject.IsCanPull)
                    {
                        msProject.IsCanPull = false;
                        msProject.ProjectVersion += 1;
                        MsProjectRepository.Update(msProject);
                    }
                }
                MsProjectEditLogRepository.Add(new MsProjectEditLog
                {
                    ProjectId = entity.ProjectId,
                    ProjectName = msProject?.Name,
                    CreatedBy = OperatorProvider.Get().YunUserGuid,
                    CreatedDate = DateTime.Now,
                    EditLogId = Guid.NewGuid(),
                    EditType = MsProjectEditTypeEnum.户型图.ToString(),
                    IsDeleted = false,
                    IsPublished = true,
                    ChangeLog = $"删除户型图：{housemapName}"
                });
            }
            await UnitOfWork.SaveChangesAsync();

            Logger.LogInformation($"【{TokenModel.Name}】批量更新户型图：[{JsonConvert.SerializeObject(ids)}]");
        }

        /// <summary>
        /// 移除项目的户型图
        /// </summary>
        /// <param name="projectId">项目Id</param>
        /// <returns></returns>
        public async Task RemoveHouseMapsByProjectId(Guid projectId)
        {
            var houseMaps = await MsHouseMapRepository.GetHouseMapByProject(projectId);
            if (houseMaps != null && houseMaps.Count > 0)
            {
                MsHouseMapRepository.RemoveRange(houseMaps);

                await UnitOfWork.SaveChangesAsync();
                Logger.LogInformation($"【{OperatorProvider.Get().Name}】清除项目：[{projectId}]下的所有户型图");
            }
        }

        /// <summary>
        /// 更改户型图名称
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        /// <exception cref="OperationException"></exception>
        public async Task HouseMapUpdateName(ProjectHouseMap model)
        {
            if (model == null)
                throw new OperationException("YB0118".SLocalize());
            //检查户型图对应项目发布
            var project = await MsProjectRepository.GetByIdAsync(model.ProjectId);
            if (project == null)
                throw new OperationException("YB0119".SLocalize());
            var entity = await MsHouseMapRepository.GetByIdAsync(model.HouseMapId);
            if (entity == null)
                throw new OperationException("YB0120".SLocalize());
            if (project.PubliceDate.HasValue)
            {
                if (entity.CreatedDate < project.PubliceDate.Value)
                    throw new OperationException("YB0121".SLocalize());
            }

            var condition = new MsHouseMapCondition() { ProjectId = model.ProjectId, Name = model.Name };
            var duplicateName = await MsHouseMapRepository.GetHouseMap(condition);
            if (duplicateName.Total > 0)
            {
                var houseMapList = duplicateName.PageData as List<ProjectHouseMap>;
                // 户型图名称是否已存在
                if (houseMapList.Where(x => string.Equals(x.Name, model.Name) && x.HouseMapId != model.HouseMapId).FirstOrDefault() != null)
                {
                    throw new OperationException("YB0122".SLocalize(model.Name));
                }
            }
            entity.Name = model.Name;
            entity.SetOperatorInfoWhenUpdate();
            MsProjectRepository.UpdateProjectVersion(entity.ProjectId);
            MsHouseMapRepository.Update(entity, x => new { x.Name, x.LastUpdatedBy, x.LastUpdatedDate, x.MeasurePoints, x.MapArea });
            await UnitOfWork.SaveChangesAsync();
            Logger.LogInformation($"【{OperatorProvider.Get().Name}】修改户型图：[{model.HouseMapId}]名称为：“{model.Name}”");
        }

        /// <summary>
        /// 户型图更新
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        /// <exception cref="OperationException"></exception>
        public async Task HouseMapUpdate(ProjectHouseMap model)
        {
            if (model == null)
                throw new OperationException("YB0118".SLocalize());
            if (model.MapArea > 100000000)
            {
                throw new OperationException("YB0123".SLocalize());
            }

            if (model.StandardMeasurePoints == null || model.StandardMeasurePoints.Count == 0)
            {
                throw new OperationException("YB0124".SLocalize());
            }

            //检查户型图对应项目
            var project = await MsProjectRepository.FirstOrDefaultAsync(x => x.ProjectId == model.ProjectId);
            if (project == null)
            {
                throw new OperationException("YB0119".SLocalize());
            }
            var houseMap = (await MsHouseMapRepository.WhereAsNoTrackingAsync(x => x.HouseMapId == model.HouseMapId)).FirstOrDefault();
            if (houseMap == null)
            {
                throw new OperationException("YB0120".SLocalize());
            }
            // 户型图名称是否已存在
            if (await MsHouseMapRepository.AnyAsync(x => x.ProjectId == model.ProjectId && x.Name == model.Name && x.HouseMapId != model.HouseMapId))
            {
                throw new OperationException("YB0122".SLocalize(model.Name));
            }
            var originExistedPoints = await MsHouseMapPointRepository.Get(model.HouseMapId);
            var projectPublishDate = project?.PubliceDate;
            bool isPointModified = false;
            var housmapCreaterdDate = houseMap.CreatedDate;

            //CAD和FMS模式的户型图站点被修改后，更新表MsHouseMap的字段PointModified为1；
            if (houseMap.DataType == 1 || houseMap.DataType == 2)
            {
                if (model.StandardMeasurePoints?.Count != originExistedPoints?.Count)
                {
                    isPointModified = true;
                }
                if (!isPointModified)
                {
                    foreach (var pointInModel in model.StandardMeasurePoints)
                    {
                        if (pointInModel.PointId == null || pointInModel.PointId == Guid.Empty)
                        {
                            isPointModified = true;
                            break;
                        }
                    }
                }
                if (isPointModified && projectPublishDate > housmapCreaterdDate)
                {
                    throw new OperationException("项目已发布不允许修改户型图");
                }
            }

            MsHouseMap entity = new MsHouseMap
            {
                HouseMapId = model.HouseMapId,
                Name = model.Name,
                MeasurePoints = model.StandardMeasurePoints.ToJsonStr(),
                Status = (EnumHouseMapStatus)model.Status,
                MapType = (EnumHouseMapType)model.MapType,
                MapArea = model.MapArea,
                ProjectId = model.ProjectId,
                HasMinus = true,
                PointModified = houseMap.PointModified == 1 ? 1 : isPointModified ? 1 : 0
            };

            if (model.StandardMeasurePoints != null && model.StandardMeasurePoints.Count > 0)
            {
                // 先删除测量点，再新增
                if (originExistedPoints != null && originExistedPoints.Count > 0)
                {
                    MsHouseMapPointRepository.RemoveRange(originExistedPoints);
                }

                // 先删除测量项，再新增
                var delMeasureItem = await MsMeasureItemRepository.Get(entity.HouseMapId);
                if (delMeasureItem != null && delMeasureItem.Count > 0)
                {
                    MsMeasureItemRepository.RemoveRange(delMeasureItem);
                }

                var measureItemTemplate = await MsMeasureTemplateRepository.GetMeasureTemplate(model.HouseMapId);        // 获取当前户型图测量项模板
                var pointTypes = await MsPointTypeRepository.GetListByProjectId(entity.ProjectId);                                                      // 获取所以站点类型

                #region 新增测量点

                List<MsHouseMapPoint> points = new List<MsHouseMapPoint>();
                List<MsMeasureItem> measureItems = new List<MsMeasureItem>();
                foreach (var item in model.StandardMeasurePoints)
                {
                    MsHouseMapPoint point = new MsHouseMapPoint();
                    point.HouseMapId = model.HouseMapId;
                    point.PointId = Guid.NewGuid();
                    point.PointIndex = item.pointIndex;
                    point.x = item.x;
                    point.y = item.y;
                    point.offsetX = item.offsetX;
                    point.offsetY = item.offsetY;
                    point.HouseTypeName = item.HouseTypeName;
                    point.HouseTypeKey = item.HouseTypeKey;
                    var pointType = pointTypes.Where(x => x.Type == item.Type && !x.IsDeleted).FirstOrDefault();
                    if (pointType == null)
                    {
                        throw new OperationException($"YB0125".SLocalize());
                    }
                    point.MsPointTypeId = pointType.Id;
                    //MsHouseMapPointRepository.Add(point);
                    points.Add(point);
                    if (item.MeasureItems == null || item.MeasureItems.Count == 0)
                    {
                        continue;
                    }

                    // 新增测量项
                    foreach (var mi in item.MeasureItems)
                    {
                        if (string.IsNullOrWhiteSpace(mi.Id) || !measureItemTemplate.Exists(x => x.Id == mi.Id))
                        {
                            continue;
                        }

                        MsMeasureItem measureItem = new MsMeasureItem();
                        measureItem.HouseMapId = model.HouseMapId;
                        measureItem.PointId = point.PointId;
                        measureItem.ItemId = Guid.NewGuid();
                        measureItem.Id = mi.Id;
                        measureItem.Title = mi.Title;
                        measureItem.Code = mi.Code;
                        measureItem.Unit = mi.Unit ?? "mm";
                        measureItems.Add(measureItem);
                    }
                }

                MsHouseMapPointRepository.AddRange(points);
                MsMeasureItemRepository.AddRange(measureItems);

                #endregion 新增测量点
            }

            #region 楼层绑定 modified on 2022/05/31 By 徐文清

            var existsedDetails = await MsHouseMapDetailsRepository.WhereAsync(x => x.ProjectId == model.ProjectId && x.HouseMapId == entity.HouseMapId);
            var dfs = existsedDetails.Select(x => new string[] { x.BuildingName, x.FloorName }).ToList();

            //需要移除的
            var needToRemove = existsedDetails.FindAll(x => !Array.Exists(model.SelectBuildAndFloorValue, y => y[0] == x.BuildingName && y[1] == x.FloorName));
            MsHouseMapDetailsRepository.RemoveRange(needToRemove, true);

            //需要新增的
            var needToInsert = new List<MsHouseMapDetails>();
            model.SelectBuildAndFloorValue.AsList().FindAll(x => !dfs.Exists(y => y[0] == x[0] && y[1] == x[1])).ForEach(df => needToInsert.Add(new MsHouseMapDetails
            {
                ProjectId = entity.ProjectId,
                BuildingName = df[0],
                FloorName = df[1],
                HouseMapDetailsGuid = Guid.NewGuid(),
                HouseMapId = entity.HouseMapId,
                IsDeleted = false
            }));
            MsHouseMapDetailsRepository.AddRange(needToInsert);

            #endregion 楼层绑定 modified on 2022/05/31 By 徐文清

            entity.SetOperatorInfoWhenUpdate();
            MsProjectRepository.UpdateProjectVersion(entity.ProjectId);
            MsHouseMapRepository.Update(entity, x => new { x.Name, x.LastUpdatedBy, x.LastUpdatedDate, x.MeasurePoints, x.MapArea, x.HasMinus, x.PointModified });
            await UnitOfWork.SaveChangesAsync();
            Logger.LogInformation($"【{TokenModel.Name}】修改了户型图信息：[housemapid;{entity.HouseMapId},housemapName:{entity.Name}]");
        }

        /// <summary>
        /// 复制户型图
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        /// <exception cref="OperationException"></exception>
        public async Task CopyHouseMapUpdate(ProjectHouseMap model)
        {
            #region 复制户型图

            var sourHouseMap = await MsHouseMapRepository.GetByIdAsync(model.HouseMapId);    // 源户型图
            if (sourHouseMap == null)
            {
                throw new OperationException($"YB0126".SLocalize());
            }
            var conditon = new MsHouseMapCondition() { ProjectId = model.ProjectId, Name = model.Name };
            var houseMaps = await MsHouseMapRepository.ExistedHouseMap(conditon);
            if (houseMaps != null && houseMaps.Total > 0)
            {
                throw new OperationException("YB0127".SLocalize(model.Name));
            }
            var destHouseMap = sourHouseMap.CopyTo<MsHouseMap>();                            // 目标户型图
            destHouseMap.HouseMapId = Guid.NewGuid();
            destHouseMap.ProjectId = model.ProjectId;
            destHouseMap.Name = model.Name;
            MsHouseMapRepository.Add(destHouseMap);                                          // 复制户型图

            #endregion 复制户型图

            #region 复制站点

            var sourHouseMapPoints = await MsHouseMapPointRepository.Get(model.HouseMapId);  // 源户型图站点
            if (sourHouseMapPoints == null || sourHouseMapPoints.Count == 0)
            {
                throw new OperationException("YB0128".SLocalize(sourHouseMap.Name));
            }
            var destHouseMapPoints = new List<MsHouseMapPoint>();
            foreach (var point in sourHouseMapPoints)
            {
                var destHouseMapPoint = point.CopyTo<MsHouseMapPoint>();
                destHouseMapPoint.HouseMapId = destHouseMap.HouseMapId;
                destHouseMapPoints.Add(destHouseMapPoint);
            }

            #endregion 复制站点

            #region 复制设计值模板

            var templates = await MsMeasureTemplateRepository.GetList(model.HouseMapId);
            var destTemplates = new List<MsMeasureTemplate>();
            foreach (var template in templates)
            {
                var destTemplate = template.CopyTo<MsMeasureTemplate>();
                destTemplate.HouseMapId = destHouseMap.HouseMapId;
                destTemplates.Add(destTemplate);
            }
            MsMeasureTemplateRepository.AddRange(destTemplates);                              // 复制设计值模板

            #endregion 复制设计值模板

            #region 复制测量项

            var measureItems = await MsMeasureItemRepository.Get(model.HouseMapId);
            var destMeasureItems = new List<MsMeasureItem>();
            measureItems?.ForEach(mi =>
            {
                var destMeasureItem = mi.CopyTo<MsMeasureItem>();
                destMeasureItem.HouseMapId = destHouseMap.HouseMapId;
                destMeasureItems.Add(destMeasureItem);
            });
            MsMeasureItemRepository.AddRange(destMeasureItems);

            #endregion 复制测量项

            #region 复制没有的房间类型数据

            var sourePointTypes = await MsPointTypeRepository.GetListByProjectId(sourHouseMap.ProjectId);
            var destPointTypes = await MsPointTypeRepository.GetListByProjectId(destHouseMap.ProjectId);
            var destIds = destPointTypes.Select(i => i.Id).ToArray();
            //var destNames = destPointTypes.Select(i => i.Name).ToArray();
            //有ID不一样的类型
            var newPointTypeList = sourePointTypes.Where(i => !destIds.Contains(i.Id)).ToArray();
            List<MsPointType> needToAddPointTypes = new List<MsPointType>();
            var soureProjectAllPointTypeMeasureItems = await MsPointTypeMeasureItemRepository.GetDataByProjects(new Guid[] { sourHouseMap.ProjectId });
            if (newPointTypeList != null && newPointTypeList.Length > 0)
            {
                foreach (var item in newPointTypeList)
                {
                    var HaveSameNameNewPointType = destPointTypes.Where(i => i.Name == item.Name).FirstOrDefault();
                    if (HaveSameNameNewPointType == null)
                    {
                        var NewMsPointType = item.CopyTo<MsPointType>();
                        NewMsPointType.ProjectGuid = destHouseMap.ProjectId;
                        NewMsPointType.MsPointTypeId = Guid.NewGuid();
                        needToAddPointTypes.Add(NewMsPointType);
                        var CurrentMsPointTypeMeasureItems = soureProjectAllPointTypeMeasureItems
                            .Where(i => i.MsPointTypeId == NewMsPointType.Id).ToList();
                        foreach (var cpmi in CurrentMsPointTypeMeasureItems)
                        {
                            MsPointTypeMeasureItem newPointTypeMeasure = new MsPointTypeMeasureItem();
                            {
                                newPointTypeMeasure.CompanyGuid = OperatorProvider.Get().CompanyGuid;
                                newPointTypeMeasure.Id = cpmi.Id;
                                newPointTypeMeasure.IsChecked = cpmi.IsChecked;
                                newPointTypeMeasure.MsPointTypeId = cpmi.MsPointTypeId;
                                newPointTypeMeasure.MsPointTypeMeasureItemId = Guid.NewGuid();
                                newPointTypeMeasure.ProjectGuid = destHouseMap.ProjectId;
                                newPointTypeMeasure.ProjectStandardId = cpmi.ProjectStandardId;
                            }
                            MsPointTypeMeasureItemRepository.Add(newPointTypeMeasure);
                        }
                    }
                    else
                    {
                        // HaveSameNameNewPointType.IsDeleted = false;
                        // MsPointTypeRepository.Update(HaveSameNameNewPointType,f=>new { f.IsDeleted });
                        var needToChangePointList = destHouseMapPoints.Where(pointItem => pointItem.MsPointTypeId == item.Id).ToArray();
                        foreach (var pointitem in needToChangePointList)
                        {
                            pointitem.MsPointTypeId = HaveSameNameNewPointType.Id;
                        }
                        //PointId关联的站点类型需要修改
                        // haveSameNameList.Add(item.Id, HaveSameNameItem.Id);
                    }
                }
                MsPointTypeRepository.AddRange(needToAddPointTypes);
            }
            MsHouseMapPointRepository.AddRange(destHouseMapPoints);

            #endregion 复制没有的房间类型数据

            MsProjectRepository.UpdateProjectVersion(model.ProjectId);

            await UnitOfWork.SaveChangesAsync();
        }

        /// <summary>
        /// 查询户型图是否已绑定FMS项目楼栋楼层
        /// </summary>
        /// <param name="houseMapId"></param>
        /// <returns></returns>
        public async Task<ApiResult> GetHouseMapBuildingFloor(Guid houseMapId)
        {
            var houseMap = await MsHouseMapBuildingFloorRepository.FirstOrDefaultAsync(p => p.HouseMapId == houseMapId && !p.IsDeleted);
            var result = houseMap == null ? null : new HouseMapBuildingFloorResponseDto
            {
                ProjectCode = houseMap.ProjectCode,
                ProjectName = houseMap.ProjectName,
                BuildingCode = houseMap.BuildingCode,
                BuildingName = houseMap.BuildingName,
                FloorCode = houseMap.FloorCode,
                FloorName = houseMap.FloorName
            };
            if (result != null)
            {
                var build = await FmsProjectBuildingFloorRepository.FirstOrDefaultAsync(p => p.ProjectCode == result.ProjectCode && !p.IsDeleted);
                result.BuildingList = build?.BuildingList.ToObject<List<FmsBuildingListDto>>();
            }
            return new ApiResult { Code = AjaxCode.Success, Result = result };
        }

        /// <summary>
        /// 更新户型图FMS楼栋楼层信息
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<ApiResult> UpdateHouseMapBuildingFloor(UpdateHouseMapBuildingFloorDto dto)
        {
            var houseMap = await MsHouseMapBuildingFloorRepository.FirstOrDefaultAsync(p => p.HouseMapId == dto.HouseMapId && !p.IsDeleted);
            if (houseMap != null)
                return new ApiResult { Code = AjaxCode.Success };

            var project = await FmsProjectBuildingFloorRepository.FirstOrDefaultAsync(p => p.ProjectCode == dto.ProjectCode);
            if (project == null)
            {
                //该Fms项目{0}不存在
                return new ApiResult { Code = AjaxCode.Fail, Message = string.Format("FmsProjectNotExists".SLocalize(), dto.ProjectCode) };
            }

            var buildingList = project.BuildingList.ToObject<List<FmsBuildingListDto>>();
            var building = buildingList.FirstOrDefault(p => p.BuildingCode == dto.BuildingCode);
            if (building == null)
            {
                //该Fms项目{0}不存在该楼栋{1}
                return new ApiResult { Code = AjaxCode.Fail, Message = string.Format("FmsBuildingNotExists".SLocalize(), dto.ProjectCode, dto.BuildingCode) };
            }
            var floor = building.FloorList.FirstOrDefault(p => p.FloorCode == dto.FloorCode);
            if (floor == null)
            {
                //该Fms项目{0}不存在该楼栋{1}楼层{2}
                return new ApiResult { Code = AjaxCode.Fail, Message = string.Format("FmsFloorNotExists".SLocalize(), dto.ProjectCode, dto.BuildingCode, dto.FloorCode) };
            }

            MsHouseMapBuildingFloorRepository.Add(new MsHouseMapBuildingFloor
            {
                HouseMapId = dto.HouseMapId,
                ProjectCode = dto.ProjectCode,
                ProjectName = dto.ProjectName,
                BuildingCode = dto.BuildingCode,
                BuildingName = dto.BuildingName,
                FloorCode = dto.FloorCode,
                FloorName = dto.FloorName,
                IsDeleted = false,
                CreatedDate = DateTime.Now,
                CreatedBy = TokenModel.Id,
                LastUpdatedBy = TokenModel.Id,
                LastUpdatedDate = DateTime.Now
            }, false);
            var affrows = await UnitOfWork.SaveChangesAsync();

            return new ApiResult { Code = affrows > 0 ? AjaxCode.Success : AjaxCode.Fail };
        }

        /// <summary>
        /// 通过FMS项目的BimMapCode得到项目模型json，然后调用自动标注算法生成户型图地图和站点位置json
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<ApiResult> CreateHouseMapByArithmetic(AddHouseMapDto dto)
        {
            var project = await CheckUserProjectAuth(dto.ProjectId);
            var housemap = await MsHouseMapRepository.FirstOrDefaultAsync(x => x.ProjectId == dto.ProjectId && x.Name == dto.Name && !x.IsDeleted);
            if (housemap != null)
                throw new OperationException($"户型图名称【{dto.Name}】已存在,请更换名称");

            //户型图Id
            var houseMapId = Guid.NewGuid();

            #region 获取内墙模型数据

            var res = await ProjectDCService.ListSpaceInnerWall(dto.ProjectCode, dto.BuildingCode, dto.FloorCode);
            if (res == null || res.Code != 0)
            {
                if (!string.IsNullOrEmpty(res?.Message))
                    Logger.LogInformation($"获取FMS项目内墙模型文件失败，BimMapCode：{dto.ProjectCode}-{dto.BuildingCode}-{dto.FloorCode}，错误信息：{res.Message}");
                return new ApiResult { Code = AjaxCode.Fail, Message = $"{"GetModeFileFailed".SLocalize()}:{res?.Message}" };
            }
            var resDataStr = res.Data.ToJsonStr();
            var innerWallFileJson = $"{project.ProjectNo}-{houseMapId}_nq.json";
            //var innerWallFilePath = Path.Combine(StartupServer.ContentRootPath, "wwwroot", UploadFile, UplaodSonFile, innerWallFileJson);
            //await File.WriteAllTextAsync(innerWallFilePath, resDataStr);
            var projectNoArr = project.ProjectNo.Split('-');
            var innerWallMinioUrl = $@"algorithm-report/{projectNoArr[0]}/{projectNoArr[1]}/AutoMatic/{houseMapId}/{innerWallFileJson}";
            var innerWallMinioPath = $"{AlgorithmReport}{innerWallMinioUrl.Replace("algorithm-report", "")}";
            var saveFolder = Directory.GetParent(innerWallMinioPath).FullName;
            if (!Directory.Exists(saveFolder))
            {
                Directory.CreateDirectory(saveFolder);
            }
            await File.WriteAllTextAsync(innerWallMinioPath, resDataStr);

            #endregion 获取内墙模型数据

            #region 获取门线模型数据

            var resstr = await ProjectDCService.FindSpaceUnit(dto.ProjectCode, dto.BuildingCode, dto.FloorCode);

            var doorLineFileJson = $"{project.ProjectNo}-{houseMapId}.json";
            var doorLineFilePath = Path.Combine(StartupServer.ContentRootPath, "wwwroot", UploadFile, UplaodSonFile, doorLineFileJson);
            await File.WriteAllTextAsync(doorLineFilePath, resstr);

            #endregion 获取门线模型数据

            var result = await ProjectDCService.ListSpaceCeiling(dto.ProjectCode, dto.BuildingCode, dto.FloorCode);
            if (result == null || result.Code != 0)
            {
                if (!string.IsNullOrEmpty(result?.Message))
                    Logger.LogInformation($"获取FMS项目天花模型文件失败，BimMapCode：{dto.ProjectCode}-{dto.BuildingCode}-{dto.FloorCode}，错误信息：{result.Message}");

                //获取Fms项目模型文件失败
                return new ApiResult { Code = AjaxCode.Fail, Message = $"{"GetModeFileFailed".SLocalize()}:{result?.Message}" };
            }

            //保存文件到指定目录
            CreateWwwrootDir();
            var fileName = $"{project.ProjectNo}-{houseMapId}-boundary.json";
            string path = Path.Combine(StartupServer.ContentRootPath, "wwwroot/" + UploadFile + "/" + UplaodSonFile + "/" + fileName);
            await File.WriteAllTextAsync(path, result.Data.ToJsonStr());

            //调用自动标注算法
            var fileUrl = $"{FileServer}/{UploadFile}/{UplaodSonFile}/{doorLineFileJson}";
            await CreateHouseMapByArithmetic(new CreateHouseMapDto
            {
                ProjectId = dto.ProjectId,
                ProjectNo = project.ProjectNo,
                HouseMapId = houseMapId,
                HouseMapName = dto.Name,
                DataType = 2,
                MapType = EnumHouseMapType.标准层,
                FileName = doorLineFileJson,
                FileUrl = fileUrl
            }, innerWallPath: innerWallMinioUrl);

            return new ApiResult { Code = AjaxCode.Success, Result = houseMapId };
        }

        /// <summary>
        /// 调用自动标注算法生成户型图地图和站点位置json
        /// </summary>
        /// <param name="dto"></param>
        /// <param name="isFmsMode">是否Fms在线模型</param>
        /// <param name="innerWallPath">内墙json路径</param>
        /// <param name="codeDto"></param>
        /// <returns></returns>
        /// <exception cref="OperationException"></exception>
        private async Task CreateHouseMapByArithmetic(CreateHouseMapDto dto, string innerWallPath = null, bool isFmsMode = false, BimMapCodeDto codeDto = null)
        {
            var autoMaticResponse = await CallArithmeticService(dto.ProjectNo, dto.HouseMapId, dto.FileName, dto.FileUrl);

            #region 操作数据库

            var map = new MsHouseMap
            {
                ProjectId = dto.ProjectId,
                HouseMapId = dto.HouseMapId,
                CreatedBy = TokenModel.Id,
                CreatedDate = DateTime.Now,
                LastUpdatedBy = TokenModel.Id,
                LastUpdatedDate = DateTime.Now,
                Name = dto.HouseMapName,
                Status = EnumHouseMapStatus.启用,
                MeasurePoints = string.Empty,
                MapType = dto.MapType,
                DataType = dto.DataType,
                Image_Base = autoMaticResponse.Image_Base,
                ExcelPath = autoMaticResponse.ExcelPath,
                InnerWallLinePath = autoMaticResponse.InnerWallLinePath,
                InnerWallPath = innerWallPath,
                IsDeleted = false,
                HasMinus = false
            };
            MsHouseMapRepository.Add(map);

            await AddMsPointList(dto.ProjectId, dto.HouseMapId, autoMaticResponse);

            //绑定FMS楼栋楼层
            if (isFmsMode && codeDto != null)
            {
                var buildingFloor = await FmsProjectBuildingFloorRepository.GetBuildingFloorName(codeDto);
                if (buildingFloor != null)
                {
                    MsHouseMapBuildingFloorRepository.Add(new MsHouseMapBuildingFloor
                    {
                        HouseMapId = dto.HouseMapId,
                        ProjectCode = buildingFloor.ProjectCode,
                        ProjectName = buildingFloor.ProjectName,
                        FloorCode = buildingFloor.FloorCode,
                        FloorName = buildingFloor.FloorName,
                        BuildingCode = buildingFloor.BuildingCode,
                        BuildingName = buildingFloor.BuildingName,
                        IsDeleted = false,
                        CreatedDate = DateTime.Now,
                        LastUpdatedDate = DateTime.Now,
                        CreatedBy = TokenModel.Id,
                        LastUpdatedBy = TokenModel.Id
                    }, false);
                }
            }

            MsProjectRepository.UpdateProjectVersion(dto.ProjectId);
            await UnitOfWork.SaveChangesAsync();

            #endregion 操作数据库
        }

        /// <summary>
        /// 更新户型图
        /// </summary>
        /// <param name="project"></param>
        /// <param name="houseMap"></param>
        /// <param name="fileName"></param>
        /// <param name="fileUrl"></param>
        /// <param name="innerWallPath"></param>
        /// <returns></returns>
        /// <exception cref="OperationException"></exception>
        private async Task UpdateHouseMapByArithmetic(MsProject project, MsHouseMap houseMap, string fileName, string fileUrl, string innerWallPath = null)
        {
            var autoMaticResponse = await CallArithmeticService(project.ProjectNo, houseMap.HouseMapId, fileName, fileUrl);

            #region 操作数据库

            //删除旧站点
            await MsHouseMapPointRepository.DeleteAsync(p => p.HouseMapId == houseMap.HouseMapId);
            await MsMeasureItemRepository.DeleteAsync(p => p.HouseMapId == houseMap.HouseMapId);

            houseMap.Image_Base = autoMaticResponse.Image_Base;
            houseMap.ExcelPath = autoMaticResponse.ExcelPath;
            houseMap.InnerWallLinePath = autoMaticResponse.InnerWallLinePath;
            houseMap.InnerWallPath = innerWallPath ?? houseMap.InnerWallPath;
            houseMap.HasMinus = false;
            MsHouseMapRepository.Update(houseMap);

            await AddMsPointList(project.ProjectId, houseMap.HouseMapId, autoMaticResponse);

            MsProjectRepository.UpdateProjectVersion(project.ProjectId);
            await UnitOfWork.SaveChangesAsync();

            #endregion 操作数据库
        }

        /// <summary>
        /// 新增户型图站点
        /// </summary>
        /// <param name="projectId">项目Id</param>
        /// <param name="houseMapId">户型图Id</param>
        /// <param name="autoMaticResponse">自动标注算法返回内容</param>
        /// <returns></returns>
        /// <exception cref="OperationException"></exception>
        private async Task AddMsPointList(Guid projectId, Guid houseMapId, AutoMaticResponseDto autoMaticResponse)
        {
            var pointTypeList = await MsPointTypeRepository.GetListByProjectId(projectId);
            var pointType = pointTypeList.FirstOrDefault(p => p.Name.Contains("房间"));
            if (pointType == null)
                pointType = pointTypeList.FirstOrDefault();
            if (pointType == null)
                throw new OperationException("YB0125".SLocalize());
            var pointList = new List<MsHouseMapPoint>();
            foreach (var item in autoMaticResponse.PointList)
            {
                pointList.Add(new MsHouseMapPoint
                {
                    HouseMapId = houseMapId,
                    PointId = Guid.NewGuid(),
                    PointIndex = item.PointId,
                    x = item.X.ToString(),
                    y = item.Y.ToString(),
                    offsetX = item.OffsetX.ToString(),
                    offsetY = item.OffsetY.ToString(),
                    Status = 1,
                    MsPointTypeId = pointType.Id
                });
            }
            MsHouseMapPointRepository.AddRange(pointList, false);
        }

        /// <summary>
        /// 调用自动标注算法生成户型图底图
        /// </summary>
        /// <param name="projectNo"></param>
        /// <param name="houseMapId"></param>
        /// <param name="fileName"></param>
        /// <param name="fileUrl"></param>
        /// <returns></returns>
        private async Task<AutoMaticResponseDto> CallArithmeticService(string projectNo, Guid houseMapId, string fileName, string fileUrl)
        {
            var codeArray = projectNo.Split("-");
            var autoMaticResponse = await AutomaticService.CreateHouseMapImage(new AutoMaticRequestDto
            {
                HouseMapId = houseMapId,
                FileName = fileName,
                FileUrl = fileUrl,
                ProjectCode = codeArray[1],
                SysOrgCode = codeArray[0]
            });
            return autoMaticResponse;
        }

        /// <summary>
        /// 检查用户对某个项目的权限（该项目是否有权限，本质上就是是否属于用户的公司的）
        /// </summary>
        /// <param name="projectId">项目Id</param>
        /// <param name="project"></param>
        /// <returns></returns>
        /// <exception cref="OperationException"></exception>
        private async Task<MsProject> CheckUserProjectAuth(Guid projectId, MsProject project = null)
        {
            var userInfo = TokenModel;
            string roleNameList = userInfo.RoleNameList;
            Guid userId = userInfo.YunUserGuid;
            Guid comId = userInfo.CompanyGuid;

            if (roleNameList.IndexOf("公司管理员") == -1 && roleNameList.IndexOf("测量管理员") == -1)
            {
                throw new OperationException("YB0103".SLocalize());
            }

            //该项目是否属于当前用户的公司
            if (project == null)
                project = await MsProjectRepository.FirstOrDefaultAsync(p => p.ProjectId == projectId && !p.IsDeleted);
            if (project == null || project.CompanyGuid != comId)
                throw new OperationException("YB0104".SLocalize());

            //如果当前用户是测量管理员，则判断该测量管理员拥有该项目的权限
            if (roleNameList.IndexOf("测量管理员") == 0)
            {
                var sql = @"select ""Id"" from ""MsUserToProject"" where ""YunProjectGuid"" = @ProjectId and ""YunUserGuid"" = @YunUserGuid";
                List<NpgsqlParameter> paras = new List<NpgsqlParameter>
                {
                    new NpgsqlParameter("@ProjectId", projectId),
                    new NpgsqlParameter("@YunUserGuid", userId)
                };
                var id = PgSqlHelper.QueryScalar<string>(sql, paras.ToArray());
                if (string.IsNullOrEmpty(id))
                {
                    throw new OperationException("YB0105".SLocalize());
                }
            }

            return project;
        }

        /// <summary>
        /// 获取户型图DXF
        /// </summary>
        /// <param name="HouseMapId">户型图ID</param>
        /// <returns></returns>
        public async Task<ApiResult> GetHouseMapDxf(Guid HouseMapId)
        {
            if (HouseMapId == Guid.Empty)
            {
                throw new OperationException("YB0009".SLocalize());
            }
            var houseMap = await MsHouseMapRepository.GetByIdAsync(HouseMapId);
            var dataType = houseMap.DataType ?? 0;

            if (dataType == 0 || string.IsNullOrEmpty(houseMap?.Image_Base))
            {
                throw new OperationException("此户型图无DXF文件");
            }

            var img_base = houseMap.Image_Base;
            var dxfPath = img_base.Replace("algorithm-report", "algorithmreport").Replace(".jpg", ".dxf");

            return new ApiResult { Code = AjaxCode.Success, Result = dxfPath };
        }
    }
}